home *** CD-ROM | disk | FTP | other *** search
/ Risc World 3 / Risc World 3.iso / SOFTWARE / ISSUE6 / PD / PDF / pdf / c++ / DrawOutputDevice < prev    next >
Text File  |  2003-02-23  |  28KB  |  1,009 lines

  1. //--------------------------------------------------------------------------
  2. //
  3. //   Copyright (c) 2002, Colin Granville
  4. //
  5. //   All rights reserved.
  6. //
  7. //   Redistribution and use in source and binary forms, with or
  8. //   without modification, are permitted provided that the following 
  9. //   conditions are met:
  10. //
  11. //      * Redistributions of source code must retain the above copyright 
  12. //        notice, this list of conditions and the following disclaimer.
  13. //
  14. //      * Redistributions in binary form must reproduce the above 
  15. //        copyright notice, this list of conditions and the following 
  16. //        disclaimer in the documentation and/or other materials 
  17. //        provided with the distribution.
  18. //
  19. //      * The name Colin Granville may not be used to endorse or promote 
  20. //        products derived from this software without specific prior 
  21. //        written permission.
  22. //
  23. //   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
  24. //   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
  25. //   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
  26. //   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
  27. //   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
  28. //   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
  29. //   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  30. //   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  31. //   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
  32. //   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  33. //   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
  34. //   OF THE POSSIBILITY OF SUCH DAMAGE.
  35. //
  36. //--------------------------------------------------------------------------
  37.  
  38. #include "DrawOutputDevice.h"
  39. #include "GuiDrawFileSprite.h"
  40. #include "GuiDrawFileFonts.h"
  41. #include "swis.h"
  42. #include "ColourSpace.h"
  43. #include "GfxState.h"
  44. #include "iostream.h"
  45. #include <math.h>
  46. #include "guilib:gfx.h"
  47. #include "GfxFont.h"
  48.  
  49. class Convert
  50. {
  51.   public:
  52.     Convert(double* matrix) : ctm(matrix) {}
  53.  
  54.     void userToDev(double x1, double y1, int& x2, int& y2)
  55.     {
  56.       x2 = (int)(ctm[0] * x1 + ctm[2] * y1 + ctm[4] + 0.5);
  57.       y2 = (int)(ctm[1] * x1 + ctm[3] * y1 + ctm[5] + 0.5);
  58.     }
  59.   private:
  60.     double* ctm;
  61. };
  62.  
  63. //*****************************************************************
  64. //*****************************************************************
  65. //*****************************************************************
  66.  
  67. DrawOutputDevice::DrawOutputDevice()
  68.  : draw("PDF"),
  69.    path(draw),
  70.    text(draw),
  71.    noImages(0),
  72.    noText(0),
  73.    noType3Fonts(0),
  74.    noDrawings(0)
  75. {
  76. }
  77.  
  78. //*****************************************************************
  79.  
  80. DrawOutputDevice::~DrawOutputDevice() {}
  81.  
  82. //*****************************************************************
  83.  
  84. GBool DrawOutputDevice::upsideDown()  {return gFalse;}
  85. GBool DrawOutputDevice::useDrawChar() {return gTrue;}
  86. GBool DrawOutputDevice::interpretType3Chars() {return !noType3Fonts;}
  87.  
  88. //*****************************************************************
  89.  
  90. void DrawOutputDevice::startPage(int /*pageNum*/, GfxState *state)
  91. {
  92.   draw.reopen();
  93.   Convert cvt(state->getCTM());
  94.   cvt.userToDev(state->getX1(),state->getY1(),bounds.xmin,bounds.ymin);
  95.   cvt.userToDev(state->getX2(),state->getY2(),bounds.xmax,bounds.ymax);
  96.   clipbox.init(bounds);
  97.  
  98.   if (font.getUsedFont(1))
  99.   {
  100.     GuiDrawFileFonts fonts(draw);
  101.     const char* fontname;
  102.     int index;
  103.     fonts.start();
  104.     for (index=1;fontname=font.getUsedFont(index),fontname;index++) fonts.add(index,fontname);
  105.     fonts.end();
  106.   }
  107. }
  108.  
  109. //*****************************************************************
  110.  
  111. void DrawOutputDevice::endPage()
  112. {
  113.   draw.endCurrentObject();
  114.   draw.setBBox(bounds);
  115.   font.clear();
  116. }
  117.  
  118. //*****************************************************************
  119.  
  120. void DrawOutputDevice::saveState(GfxState*)
  121. {
  122.   clipbox.push();
  123. }
  124.  
  125. //*****************************************************************
  126.  
  127. void DrawOutputDevice::restoreState(GfxState* state)
  128. {
  129.   clipbox.pop();
  130.   updateAll(state);
  131. }
  132.  
  133. //*****************************************************************
  134.  
  135. void DrawOutputDevice::setClip(GfxState* state, int isEo)
  136. {
  137.   // a bodge but its better than nothing
  138.  
  139.   GfxPath& gfx_path=*state->getPath();
  140.   if (gfx_path.getNumSubpaths()==0) return;
  141.  
  142.   int i;
  143.   int pathSize=0;
  144.   for (i=0;i<gfx_path.getNumSubpaths();i++)
  145.   {
  146.     GfxSubpath& subpath= *(gfx_path.getSubpath(i));
  147.     int number_of_points=subpath.getNumPoints();
  148.     if (number_of_points<2) continue;
  149.     int n;
  150.     pathSize+=3;
  151.     for (n=1;n<number_of_points;n++)
  152.     {
  153.       if (subpath.getCurve(n))
  154.       {
  155.         pathSize+=7; n+=2;
  156.       }
  157.       else
  158.       {
  159.         pathSize+=3;
  160.       }
  161.     }
  162.     if (subpath.isClosed()) pathSize++;
  163.   }
  164.  
  165.   if (pathSize)
  166.   {
  167.     int* path=new int[pathSize+4];
  168.     if (!path) return;
  169.  
  170.     int pos=0;
  171.     path[pos++]=pathSize+4;
  172.     path[pos++]=isEo;
  173.     int x,y;
  174.     Convert cvt(state->getCTM());
  175.  
  176.     for (i=0;i<gfx_path.getNumSubpaths();i++)
  177.     {
  178.       GfxSubpath& subpath= *(gfx_path.getSubpath(i));
  179.       int number_of_points=subpath.getNumPoints();
  180.       if (number_of_points<2) continue;
  181.  
  182.       path[pos++]=2;
  183.       cvt.userToDev(subpath.getX(0),subpath.getY(0),x,y);
  184.       path[pos++]=x; path[pos++]=y;
  185.  
  186.       int n;
  187.       for (n=1;n<number_of_points;n++)
  188.       {
  189.         if (subpath.getCurve(n))
  190.         {
  191.            path[pos++]=6;
  192.            cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  193.            path[pos++]=x;  path[pos++]=y;  n++;
  194.            cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  195.            path[pos++]=x;  path[pos++]=y;  n++;
  196.            cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  197.            path[pos++]=x;  path[pos++]=y;
  198.         }
  199.         else
  200.         {
  201.            path[pos++]=8;
  202.            cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  203.            path[pos++]=x;  path[pos++]=y;
  204.         }
  205.       }
  206.       if (subpath.isClosed()) path[pos++]=5;
  207.     }
  208.     path[pos]=0;
  209.     clipbox.setPath(path);
  210.   }
  211. }
  212.  
  213. //*****************************************************************
  214.  
  215. void DrawOutputDevice::clip(GfxState* state)
  216. {
  217.   setClip(state,0);
  218. }
  219.  
  220. //*****************************************************************
  221.  
  222. void DrawOutputDevice::eoClip(GfxState* state)
  223. {
  224.   setClip(state,1);
  225. }
  226.  
  227. //*****************************************************************
  228. void DrawOutputDevice::updateLineJoin(GfxState* state)
  229. {
  230.   pathState.setJoin(state->getLineJoin());
  231. }
  232.  
  233. //*****************************************************************
  234.  
  235. void DrawOutputDevice::updateLineCap(GfxState* state)
  236. {
  237.   pathState.setStartCap(state->getLineCap());
  238.   pathState.setEndCap(pathState.getStartCap());
  239. }
  240.  
  241. //*****************************************************************
  242.  
  243. void DrawOutputDevice::updateLineWidth(GfxState* state)
  244. {
  245.   pathState.setOutlineWidth((unsigned int)state->getTransformedLineWidth());
  246. }
  247.  
  248. //*****************************************************************
  249.  
  250. inline unsigned int getColour(GfxRGB& rgb)
  251. {
  252.   unsigned int r=(unsigned int)(rgb.r*256.0);
  253.   if (r>=255) r=255;
  254.   unsigned int g=(unsigned int)(rgb.g*256.0);
  255.   if (g>=255) g=255;
  256.   unsigned int b=(unsigned int)(rgb.b*256.0);
  257.   if (b>255) b=255;
  258.   return (r<<8) | (g<<16) | (b<<24);
  259. }
  260.  
  261. //*****************************************************************
  262.  
  263. void DrawOutputDevice::updateFillColor(GfxState* state)
  264. {
  265.   GfxRGB rgb;
  266.   state->getFillRGB(&rgb);
  267.   pathState.setFillColour(getColour(rgb));
  268. }
  269.  
  270. //*****************************************************************
  271.  
  272. void DrawOutputDevice::updateStrokeColor(GfxState*state)
  273. {
  274.   GfxRGB rgb;
  275.   state->getStrokeRGB(&rgb);
  276.   pathState.setOutlineColour(getColour(rgb));
  277. }
  278.  
  279. //*****************************************************************
  280.  
  281. bool DrawOutputDevice::doPath(GfxState* state)
  282. {
  283.   int i;
  284.   GfxPath& gfx_path=*state->getPath();
  285.   int mask;
  286.   Convert cvt(state->getCTM());
  287.   for (i=0;i<gfx_path.getNumSubpaths();i++)
  288.   {
  289.     GfxSubpath& subpath= *(gfx_path.getSubpath(i));
  290.     int number_of_points=subpath.getNumPoints();
  291.     if (number_of_points<2) continue;
  292.  
  293.     path.moveTo();
  294.     int x,y;
  295.     cvt.userToDev(subpath.getX(0),subpath.getY(0),x,y);
  296.     mask=clipbox.clip(x,y);
  297.     path.point(x,y);
  298.     int n;
  299.     for (n=1;n<number_of_points;n++)
  300.     {
  301.       if (subpath.getCurve(n))
  302.       {
  303.         path.bezierTo();
  304.         cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  305.         mask &= clipbox.clip(x,y);
  306.         path.point(x,y); n++;
  307.  
  308.         cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  309.         mask &= clipbox.clip(x,y);
  310.         path.point(x,y); n++;
  311.  
  312.         cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  313.         mask &= clipbox.clip(x,y);
  314.         path.point(x,y);
  315.       }
  316.       else
  317.       {
  318.         path.drawTo();
  319.         cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
  320.         mask &= clipbox.clip(x,y);
  321.         path.point(x,y);
  322.       }
  323.     }
  324.     if (subpath.isClosed()) path.closeSubPath();
  325.   } 
  326.  
  327.   // removal of paths outside clipbox
  328.   // mask is nonzero if all points have an x or y clipped on the same side
  329.  
  330.   return mask==0;
  331. }
  332.  
  333. //*****************************************************************
  334.  
  335. //----- path painting
  336. void DrawOutputDevice::stroke(GfxState* state)
  337. {
  338.   if (noDrawings) return;
  339.  
  340.   if (pathState.getOutlineColour() == GuiDrawFilePathState::OFF ||
  341.       !state->isPath()) return;
  342.  
  343.   unsigned int fill_colour = pathState.getFillColour();
  344.   pathState.setFillColour(GuiDrawFilePathState::OFF);
  345.   path.start();
  346.  
  347.   double* pattern;
  348.   int     length;
  349.   double  start;
  350.   state->getLineDash(&pattern,&length,&start);
  351.   pathState.setDashPattern(length);
  352.   if (length)
  353.   {
  354.     path.dashPattern((int)state->transformWidth(start),length);
  355.     for (;length;length--) path.dashElement((unsigned int)state->transformWidth(*pattern++));
  356.   }
  357.   
  358.   if (doPath(state)) path.end(pathState); //if you don't end a path it's ignored
  359.  
  360.   pathState.setDashPattern();
  361.   pathState.setFillColour(fill_colour);
  362. }
  363.  
  364. //*****************************************************************
  365.  
  366.  
  367. ostream& operator<<(ostream& out,const GuiBBox& box)
  368. {
  369.   out << box.xmin << ' ' << box.ymin << ' ' << box.xmax << ' ' << box.ymax;
  370.   return out;
  371. }
  372.  
  373. inline bool contains(const GuiBBox a,const GuiBBox& b)
  374. {
  375.   return (b.xmin>=a.xmin && b.ymin>=a.ymin &&
  376.           b.xmax<=a.xmax && b.ymax<=a.ymax);
  377. }
  378.  
  379. inline void clipTo(Clip& clipbox,int x,int y,int& ox, int& oy)
  380. {
  381.   clipbox.clip(x,y);
  382.   ox=x;
  383.   oy=y;
  384. }
  385.  
  386. bool DrawOutputDevice::doRectanglePath(GfxState* state)
  387. {
  388.   if (!(clipbox.getPath() || clipbox.getBBox() )) return 0;
  389.   GfxPath *gfxpath=state->getPath();
  390.  
  391.   if (gfxpath->getNumSubpaths()==1 &&
  392.       gfxpath->getSubpath(0)->getNumPoints() == 5)
  393.   {
  394.     GfxSubpath* subpath = gfxpath->getSubpath(0);
  395.     struct {int x,y; } pt[5];
  396.     Convert cvt(state->getCTM());
  397.     for (int i=0;i<5;i++)
  398.     {
  399.       cvt.userToDev(subpath->getX(i),subpath->getY(i),pt[i].x,pt[i].y);
  400.     }
  401.     GuiBBox box;
  402.     box.xmin=pt[0].x;
  403.     box.xmax=pt[2].x;
  404.     box.ymin=pt[0].y;
  405.     box.ymax=pt[2].y;
  406.  
  407.     if (!( box.xmin==pt[4].x && box.ymin==pt[4].y &&
  408.            ((box.xmin==pt[1].x && box.ymin == pt[3].y &&
  409.              box.xmax==pt[3].x && box.ymax == pt[1].y) ||
  410.             (box.xmin==pt[3].x && box.ymin == pt[1].y &&
  411.              box.xmax==pt[1].x && box.ymax == pt[3].y)) 
  412.        )) return 0;
  413.  
  414.     if (box.xmin>box.xmax) {int temp=box.xmin;box.xmin=box.xmax;box.xmax=temp;}
  415.     if (box.ymin>box.ymax) {int temp=box.ymin;box.ymin=box.ymax;box.ymax=temp;}
  416.  
  417.     if (!contains(box,*clipbox.getBBox()) )
  418.     {
  419.       if (!contains(*clipbox.getBBox(),box) ) return 0;     
  420.       path.moveTo();
  421.       path.point(pt[0].x,pt[0].y);
  422.       path.drawTo();
  423.       path.point(pt[1].x,pt[1].y);
  424.       path.drawTo();
  425.       path.point(pt[2].x,pt[2].y);
  426.       path.drawTo();
  427.       path.point(pt[3].x,pt[3].y);
  428.       path.closeSubPath();
  429.       return 1;
  430.     }
  431.     
  432.     int x,y;
  433.     for (const int* p=clipbox.getPath()+2;*p!=0;p++)
  434.     {
  435.       switch (*p)
  436.       {
  437.         case 2:  path.moveTo();
  438.                  clipTo(clipbox,p[1],p[2],x,y);
  439.                  path.point(x,y);
  440.                  p+=2;
  441.                  break;
  442.         case 8:  path.drawTo();
  443.                  clipTo(clipbox,p[1],p[2],x,y);
  444.                  path.point(x,y);
  445.                  p+=2;
  446.                  break;
  447.         case 5:  path.closeSubPath();
  448.                  break;
  449.         case 6:  path.bezierTo();
  450.                  clipTo(clipbox,p[1],p[2],x,y);
  451.                  path.point(x,y);
  452.                  clipTo(clipbox,p[3],p[4],x,y);
  453.                  path.point(x,y);
  454.                  clipTo(clipbox,p[5],p[6],x,y);
  455.                  path.point(x,y);
  456.                  p+=6;
  457.                  break;
  458.       }
  459.     }
  460.  
  461.     return 1;    
  462.   }
  463.   return 0;
  464. }
  465.  
  466. //*****************************************************************
  467.  
  468. void DrawOutputDevice::fill(GfxState* state)
  469. {
  470.   if (noDrawings) return;
  471.  
  472.   if (pathState.getFillColour() == GuiDrawFilePathState::OFF) return;
  473.   unsigned int outline_colour = pathState.getOutlineColour();
  474.   pathState.setOutlineColour(GuiDrawFilePathState::OFF);
  475.   pathState.setWindingRule(GuiDrawFilePathState::NON_ZERO);
  476.   path.start();
  477.   if (doRectanglePath(state) || doPath(state)) path.end(pathState);
  478.   pathState.setOutlineColour(outline_colour);
  479. }
  480.  
  481. //*****************************************************************
  482.  
  483. void DrawOutputDevice::eoFill(GfxState* state)
  484. {
  485.   if (noDrawings) return;
  486.  
  487.   if (pathState.getFillColour() == GuiDrawFilePathState::OFF) return;
  488.   unsigned int outline_colour = pathState.getOutlineColour();
  489.   pathState.setOutlineColour(GuiDrawFilePathState::OFF);
  490.   pathState.setWindingRule(GuiDrawFilePathState::EVEN_ODD);
  491.   path.start();
  492.   if (doRectanglePath(state) || doPath(state)) path.end(pathState);
  493.  
  494.   pathState.setOutlineColour(outline_colour);
  495. }
  496.  
  497. //*****************************************************************
  498.  
  499. void DrawOutputDevice::updateFont(GfxState *state)
  500. {
  501.   updateRender(state);
  502.   font.set(*state);
  503. }
  504.  
  505. //*****************************************************************
  506.  
  507. void DrawOutputDevice::updateRender(GfxState *state)
  508. {
  509. }
  510. //*****************************************************************
  511.  
  512. static Unicode* getLigature(Unicode u,int &len)
  513. {
  514.   static Unicode ff[]= {'f','f'};
  515.   static Unicode ffi[]= {'f','f','i'};
  516.   static Unicode ffl[]= {'f','f','l'};
  517.   switch (u)
  518.   {
  519.     case 0xFB00: len=2;return ff;
  520.     case 0xFB03: len=3;return ffi;
  521.     case 0xFB04: len=3;return ffl;
  522.   }
  523.   return 0;
  524. }
  525. void DrawOutputDevice::drawChar(GfxState *state, double x, double y,
  526.                         double dx, double dy,
  527.                         double originX, double originY,
  528.                         CharCode code, Unicode *uni, int uLen)
  529. {
  530.   if (noText || uLen<=0) return;
  531.  
  532.   if (state->getRender() & 1)
  533.   {
  534.     font.foreColour = pathState.getOutlineColour();
  535.     font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
  536.   }
  537.   else 
  538.   {
  539.     font.foreColour = pathState.getFillColour();
  540.     font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
  541.   }
  542.   Unicode* u=uni;
  543.   unsigned int ch=font.getChar(u[0]);
  544.   if (!ch) u=getLigature(u[0],uLen);
  545.   if (u)
  546.   {
  547.     text.start();
  548.     double width=0;
  549.     int i;
  550.     for (i=0;i<uLen;i++)
  551.     {
  552.       ch=font.getChar(u[i]);
  553.       if (ch)
  554.       {
  555.         width+=font.getCharWidth(ch);
  556.         text.put(ch);
  557.       }
  558.     }
  559.     Convert cvt(state->getCTM());
  560.     cvt.userToDev(x,y,font.x,font.y);
  561.     font.setCharMatrix(originX,width);
  562.     text.end(font,font.getHandle());
  563.   }
  564. }
  565.  
  566. //*****************************************************************
  567.  
  568. void DrawOutputDevice::drawString(GfxState *state, GString *s)
  569. {
  570.   if (noText) return;
  571.  
  572.   if (state->getRender() & 1)
  573.   {
  574.     font.foreColour = pathState.getOutlineColour();
  575.     font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
  576.   }
  577.   else 
  578.   {
  579.     font.foreColour = pathState.getFillColour();
  580.     font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
  581.   }
  582.  
  583.   GfxFont* fnt=state->getFont();
  584.   if (!fnt) return;
  585.  
  586.   double      x=0;
  587.   char*       p=s->getCString();
  588.   int         len= s->getLength();
  589.   Unicode     uni[8];
  590.   int         uLen;
  591.   CharCode    code;
  592.   double      xtotal=0;
  593.   double      dummy;
  594.   int         nChars=0;
  595.   int         nSpaces=0;
  596.   double      width=0;
  597.  
  598.   Convert cvt(state->getCTM());
  599.   cvt.userToDev(state->getCurX(),state->getCurY(),font.x,font.y);
  600.   text.start();
  601.   while (len > 0) 
  602.   {
  603.     Unicode* u=uni;
  604.     int n = fnt->getNextChar(p, len, &code,
  605.                           u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
  606.                           &x, &dummy, &dummy, &dummy);
  607.  
  608.     unsigned int ch=font.getChar(u[0]);
  609.     if (!ch) u=getLigature(u[0],uLen);
  610.   
  611.     if (u)
  612.     {
  613.       int i;
  614.       for (i=0;i<uLen;i++)
  615.       {
  616.         ch=font.getChar(u[i]);
  617.         if (ch)
  618.         {
  619.            text.put(ch);
  620.            width+=font.getCharWidth(ch);
  621.         }
  622.       }
  623.     }
  624.     xtotal+=x;
  625.     if (n == 1 && *p == ' ')
  626.     {
  627.       ++nSpaces;
  628.     }
  629.     ++nChars;
  630.     p += n;
  631.     len -= n;
  632.   }
  633.   if (nChars && state->getCharSpace()!=0)
  634.       xtotal+=nChars * state->getCharSpace()/state->getFontSize();
  635.   if (nSpaces && state->getWordSpace()!=0)
  636.       xtotal+=nSpaces * state->getWordSpace()/state->getFontSize();
  637.   font.setCharMatrix(xtotal,width);
  638.   text.end(font,font.getHandle());
  639. }
  640. //*****************************************************************
  641.  
  642. //scales draw units dpi to image dpi * (1<<16) 
  643. #define IMAGE_SCALE_FACTOR 128
  644.  
  645. class ReverseSamples
  646. {
  647.   public:
  648.     ReverseSamples();
  649.     void         setbpc(int bpc)   {
  650.                                      if      (bpc>4) b=b8;
  651.                                      else if (bpc>2) b=b4;
  652.                                      else if (bpc>1) b=b2;
  653.                                      else            b=b1;
  654.                                    }
  655.     unsigned int sample(unsigned char c) {return b[c];}
  656.   private:
  657.     unsigned char b1[256];
  658.     unsigned char b2[256];
  659.     unsigned char b4[256];
  660.     unsigned char b8[256];
  661.     unsigned char* b;
  662.  
  663. };
  664.  
  665. ReverseSamples::ReverseSamples()
  666. {
  667.   unsigned int i;
  668.   b=b8;
  669.   for (i=0;i<256;i++) 
  670.   {
  671.     b1[i] = ((i & 1) << 7) |
  672.             ((i & 2) << 5) |
  673.             ((i & 4) << 3) |
  674.             ((i & 8) << 1) |
  675.             ((i & 16) >> 1) |
  676.             ((i & 32) >> 3) |
  677.             ((i & 64) >> 5) |
  678.             ((i & 128) >> 7);
  679.  
  680.     b2[i] = ((i & 3) << 6) |
  681.             ((i & 0xc)<< 2) |
  682.             ((i & 0x30) >> 2) |
  683.             ((i & 0xC0) >> 6);
  684.  
  685.     b4[i] =  ((i & 0xf) << 4) |
  686.              ((i & 0xf0) >> 4);
  687.     b8[i]=i;
  688.   }
  689. }
  690.  
  691. ReverseSamples reverse;
  692.  
  693. //*****************************************************************
  694.  
  695. void DrawOutputDevice::drawImageMask(GfxState *state, Object* /*ref*/, Stream *str,
  696.                                      int width, int height, GBool invert,
  697.                                      GBool /*inlineImg*/)
  698. {
  699.   if (width==0 || height==0 || noImages) return;
  700.   str->reset();
  701.  
  702.   GuiDrawFileSprite sprite(draw);
  703.   sprite.start(width,height,1);
  704.   sprite.put(pathState.getFillColour());
  705.   sprite.put(pathState.getFillColour());
  706.   sprite.put(0); 
  707.   sprite.put(0);
  708.  
  709.   unsigned int bits=width-1;
  710.   int h,w;
  711.   sprite.startImage();
  712.   for (h=height;h;h--)
  713.   {
  714.     for (w=bits;w>=0;w-=32) sprite.put(0);
  715.   }
  716.   sprite.startMask();
  717.   reverse.setbpc(1);
  718.   unsigned int n;
  719. //  cerr << bits << ' ' << width << ' ' << height << endl;
  720.   unsigned int invertbits= (invert ? 0:-1u);
  721.   for (h=height;h;h--)
  722.   {
  723.     for (w=bits;w>=0;w-=32)
  724.     {
  725.       n=reverse.sample(str->getChar());
  726.       if (w>=8) n|=(reverse.sample(str->getChar()) << 8);
  727.       if (w>=16) n|=(reverse.sample(str->getChar()) << 16);
  728.       if (w>=24) n|=(reverse.sample(str->getChar()) << 24);
  729.       sprite.put(n^invertbits);
  730.     }
  731.   }
  732.  
  733.  
  734.   { // calculate transform matrix and bounds
  735.     GuiBBox           bounds;
  736.  
  737.     double* mat=state->getCTM();
  738.     Convert cvt(mat);
  739.  
  740.     GuiTransform      matrix;
  741.     matrix.m0 = (int)( mat[0] * IMAGE_SCALE_FACTOR /width);
  742.     matrix.m1 = (int)( mat[1] * IMAGE_SCALE_FACTOR /width);
  743.     matrix.m2 = (int)( mat[2] * IMAGE_SCALE_FACTOR /height);
  744.     matrix.m3 = (int)( mat[3] * IMAGE_SCALE_FACTOR /height);
  745.     
  746.     Boundary_start(bounds);
  747.     int x,y;
  748.     cvt.userToDev(0.0,0.0,x,y);
  749.     matrix.m4 = x;
  750.     matrix.m5 = y;
  751.     Boundary_point(bounds,x,y);
  752.     cvt.userToDev(0.0,1.0,x,y);
  753.     Boundary_point(bounds,x,y);   
  754.     cvt.userToDev(1.0,1.0,x,y);
  755.     Boundary_point(bounds,x,y);   
  756.     cvt.userToDev(1.0,0.0,x,y);
  757.     Boundary_point(bounds,x,y);   
  758.     sprite.end(matrix,bounds);
  759.   }
  760. }
  761. //*****************************************************************
  762.  
  763. void DrawOutputDevice::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
  764.                          int width, int height, GfxImageColorMap *colorMap,
  765.                          int */*maskColors*/, GBool /*inlineImg*/)
  766. {
  767.   if (width==0 || height==0 || noImages) return;
  768.  
  769.  
  770.   int bpc    = colorMap->getBits();
  771.   int ncomps = colorMap->getNumPixelComps();
  772.  
  773.   str->reset();
  774.  
  775.   ColourSpace* colourSpace=makeColourSpace(colorMap->getColorSpace());
  776.   GuiDrawFileSprite sprite(draw);
  777. //  cerr << "mode " << colorMap->getColorSpace()->getMode() << endl;
  778. //  cerr << bpc << ' ' << ncomps << ' ' << width << ' ' << height << endl;
  779. //  cerr << "decode " << colorMap->getDecodeLow(0) << ' ' << colorMap->getDecodeHigh(0) << endl;
  780.   if (ncomps == 1 &&
  781.      (bpc<8 || (bpc==8 && width*height*3>2048) ) )
  782.   {
  783.     int step;
  784.     switch (bpc)
  785.     {
  786.       case 1: step=0xff;break;
  787.       case 2: step=0x55;break;
  788.       case 4: step=0x11;break;
  789.       case 8: step=1;   break;
  790.       default: delete colourSpace;return; //illegal bpc
  791.     }
  792.     sprite.start(width,height,bpc);
  793.     if (draw.hasFailed())
  794.     {
  795.       delete colourSpace;
  796.       return;
  797.     }
  798.  
  799.     if (colorMap->getColorSpace()->getMode()==csIndexed)
  800.     {
  801.       int col;
  802.       int i;
  803.       for (col=0,i=0;i<256;i+=step,col++)
  804.       {           
  805.         unsigned int n=colourSpace->getRGB((unsigned char*)&col);
  806.   //      cerr << n << endl;
  807.         sprite.put(n);
  808.         sprite.put(n);
  809.       }
  810.     }
  811.     else
  812.     {
  813.       unsigned int invert=(colorMap->getDecodeLow(0) > colorMap->getDecodeHigh(0) ? 0xffffff00 : 0);
  814.       int i;
  815.       for (i=0;i<256;i+=step)
  816.       {            
  817.         unsigned int n=colourSpace->getRGB((unsigned char*)&i)^invert;
  818.   //      cerr << n << endl;
  819.         sprite.put(n);
  820.         sprite.put(n);
  821.       }
  822.     }
  823.  
  824.     sprite.startImage();
  825.     reverse.setbpc(bpc);
  826.     unsigned int bits=width*bpc-1;
  827.     int h,w;
  828.     unsigned int n;
  829.     for (h=height;h;h--)
  830.     {
  831.       for (w=bits;w>=0;w-=32)
  832.       {
  833.         n=reverse.sample(str->getChar());
  834.         if (w>=8) n|=(reverse.sample(str->getChar()) << 8);
  835.         if (w>=16) n|=(reverse.sample(str->getChar()) << 16);
  836.         if (w>=24) n|=(reverse.sample(str->getChar()) << 24);
  837.         sprite.put(n);
  838.       }
  839.     }
  840.   }
  841.   else if (bpc == 8)
  842.   { 
  843.     sprite.start(width,height,32);
  844.     if (draw.hasFailed())
  845.     {
  846.       delete colourSpace;
  847.       return;
  848.     }
  849.     sprite.startImage();
  850.     unsigned char n[8];
  851.     int i;
  852.     int c;
  853.     int comps=ncomps;
  854.     if (comps>8) comps=8; //shouldn't happen but you never know
  855.     for (i=width*height;i;i--)
  856.     {
  857.       for (c=0;c<comps;c++) n[c] = str->getChar();
  858.       sprite.put(colourSpace->getRGB(n)>>8);
  859.     } 
  860.   } 
  861.   else 
  862.   {
  863.     static unsigned char col1[] = {0,0xff};
  864.     static unsigned char col2[] = {0,0x55,0xaa,0xff};
  865.     static unsigned char col4[] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
  866.                                    0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
  867.     unsigned char* colour;
  868.  
  869.     sprite.start(width,height,32);
  870.     if (draw.hasFailed())
  871.     {
  872.       delete colourSpace;
  873.       return;
  874.     }
  875.     sprite.startImage();
  876.     int shift;
  877.     switch (bpc)
  878.     {
  879.       case 1:  shift=1;colour=col1;break;
  880.       case 2:  shift=2;colour=col2;break;
  881.       default: shift=4;colour=col4;break;
  882.     }
  883.     unsigned char n[8];
  884.     int c;
  885.     int comps=ncomps;
  886.     if (comps>8) comps=8; //shouldn't happen but you never know
  887.     int buffer;
  888.     int h,w;
  889.  
  890.     for (h=height;h;h--)
  891.     {
  892.       buffer=0x1000000;
  893.       for (w=width;w;w--)
  894.       {
  895.         for (c=0;c<comps;c++) 
  896.         { 
  897.           if (buffer >= 0x1000000) { buffer=str->getChar(); buffer |=  0x10000;} 
  898.           buffer <<=shift;
  899.           n[c]= colour[(buffer >> 8) & 0xf];
  900.         }
  901.         sprite.put(colourSpace->getRGB(n)>>8);
  902.       }
  903.     } 
  904.   }
  905.  
  906.   delete colourSpace;
  907.   
  908.   { // calculate transform matrix and bounds
  909.     GuiBBox           bounds;
  910.  
  911.     double* mat=state->getCTM();
  912.     Convert cvt(mat);
  913.  
  914.     GuiTransform      matrix;
  915.     matrix.m0 = (int)( mat[0] * IMAGE_SCALE_FACTOR /width);
  916.     matrix.m1 = (int)( mat[1] * IMAGE_SCALE_FACTOR /width);
  917.     matrix.m2 = (int)( mat[2] * IMAGE_SCALE_FACTOR /height);
  918.     matrix.m3 = (int)( mat[3] * IMAGE_SCALE_FACTOR /height);
  919.     Boundary_start(bounds);
  920.     int x,y;
  921.     cvt.userToDev(0.0,0.0,x,y);
  922.     matrix.m4 = x;
  923.     matrix.m5 = y;
  924.     Boundary_point(bounds,x,y);
  925.     cvt.userToDev(0.0,1.0,x,y);
  926.     Boundary_point(bounds,x,y);   
  927.     cvt.userToDev(1.0,1.0,x,y);
  928.     Boundary_point(bounds,x,y);   
  929.     cvt.userToDev(1.0,0.0,x,y);
  930.     Boundary_point(bounds,x,y); 
  931.  
  932.     if (clipbox.getPath()) sprite.startMaskFill();
  933.     sprite.end(matrix,bounds);
  934.  
  935.     if (draw.hasFailed()) return;
  936.  
  937. //cerr << "SPRITE" << endl;
  938.     if (clipbox.getPath())
  939.     {
  940.       GuiTransform pathMatrix;
  941.  
  942.       {
  943.         //extend stack so that sprite ptr doesn't move
  944.         char a[256];
  945.  
  946.         //invert matrix
  947.         double m[4], om[4];
  948.         m[0]=((double)matrix.m0)/0x10000;
  949.         m[1]=((double)matrix.m1)/0x10000;
  950.         m[2]=((double)matrix.m2)/0x10000;
  951.         m[3]=((double)matrix.m3)/0x10000;
  952.         double det=1/(m[0]*m[3] - m[1]*m[2]);
  953. //cerr << "m "<< m[0] <<',' << m[1] <<',' << m[2] <<',' << m[3] << endl;
  954.         om[0]=m[3]*det;
  955.         om[1]=-m[1]*det;
  956.         om[2]=-m[2]*det;
  957.         om[3]=m[0]*det;
  958. //cerr << "om "<< om[0] <<',' << om[1] <<',' << om[2] <<',' << om[3] << endl;
  959.  
  960.  
  961.         pathMatrix.m0=(int)(om[0]*0x10000);
  962.         pathMatrix.m1=(int)(om[1]*0x10000);
  963.         pathMatrix.m2=(int)(om[2]*0x10000);
  964.         pathMatrix.m3=(int)(om[3]*0x10000);
  965.         pathMatrix.m4=(int)((m[2]*(double)matrix.m5-m[3]*(double)matrix.m4)*det);
  966.         pathMatrix.m5=(int)((m[1]*(double)matrix.m4-m[0]*(double)matrix.m5)*det);
  967.       }
  968.  
  969.       int r1,r2,r3;
  970.       char* spr=sprite.getPtr();
  971.  
  972.       _kernel_oserror* err=_swix(OS_SpriteOp,_INR(0,3) | _OUTR(1,3),0x200+61,spr,spr,0,&r1,&r2,&r3);
  973.       if (err==0)
  974.       {
  975.         _swix(ColourTrans_SetColour,_IN(0)|_INR(3,4),0xff,0,0);
  976.         err=_swix(Draw_Fill,_INR(0,3),clipbox.getPath()+2,0,&pathMatrix,0);
  977.         _swix(OS_SpriteOp,_INR(0,3),0x200+61,r1,r2,r3);
  978.       }
  979. //      cerr << matrix.m0 << ' ' << matrix.m1 << endl;
  980. //      cerr << matrix.m2 << ' ' << matrix.m3 << endl;
  981. //      cerr << matrix.m4 << ' ' << matrix.m5 << endl;
  982. //      cerr <<"xy " << matrix.m4/256 <<',' << matrix.m5/256 << endl;
  983. //      int* p=clipbox.getPath();
  984. //      int i;
  985. //      cerr << "++++++++" << endl;
  986. //      for (i=0;i<p[0]-1;i++)
  987. //      {
  988. //          cerr << p[i];
  989. //          switch (p[i])
  990. //          {
  991. //             case 6: cerr << ' ' 
  992. //                          << p[i+1] << ',' << p[i+2] << ' '
  993. //                          << p[i+3] << ',' << p[i+5] << ' '
  994. //                          << p[i+5] << ',' << p[i+6];
  995. //                     i+=6;
  996. //                     break;
  997. //             case 2:
  998. //             case 8: cerr << ' ' 
  999. //                          << p[i+1]/256 << ',' << p[i+2]/256;
  1000. //                     i+=2;
  1001. //                     break;
  1002. //          }
  1003. //          cerr << endl;
  1004. //      }
  1005. //      cerr << "--------" << endl;
  1006.     }
  1007.   }
  1008. }
  1009.